<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    progress {
      width: 300px;
      height: 20px;
      margin: 10px 0;
    }

    #status {
      font-size: 16px;
      margin-top: 5px;
    }

    #loading {
      margin: 10px 0;
      font-size: 14px;
      color: #888;
    }

    /* 简单旋转动画 */
    .spinner {
      border: 3px solid #f3f3f3;
      border-top: 3px solid #3498db;
      border-radius: 50%;
      width: 24px;
      height: 24px;
      animation: spin 1s linear infinite;
      display: inline-block;
      vertical-align: middle;
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }
  </style>
</head>

<body>

  <div>
    <h3>使用普通引入的方式加载一个图片</h3>
    <img src="./image.svg" />
  </div>

  <div>
    <h3>使用流加载</h3>
    <img id='target' />
  </div>

  <div>

    <h3>流加载（带进度）</h3>
    <div>
      加载进度-本地需要搞一个大一点的图片， 比如 1M的 ，会很明显有过程
    </div>
    <div id="loading">
      <span class="spinner"></span> 加载中...
    </div>
    <progress id="progressBar" value="0" max="100"></progress>
    <div id="status">0%</div>
    <img id="target3" style="max-width: 400px; margin-top: 10px;" />
  </div>


  <script>
    const image = document.querySelector('#target');
    const image3 = document.querySelector('#target3');
    const progressBar = document.querySelector('#progressBar');
    const statusText = document.querySelector('#status');
    const loadingIndicator = document.querySelector('#loading');

    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); // 人为延迟


    const run = async () => {
      try {
        const response = await fetch('./image.svg');

        console.log(response);
        // 这里的 body 是一个 ReadableStream 对象
        const reader = response.body.getReader();

        // 	new ReadableStream 创建一个自定义的读取流对象
        const rs = await new ReadableStream({
          // 	start 当流开始时会执行这个函数 - 这是内置的函数
          async start (controller) {
            while (true) {
              // 	reader.read 从上面获取的 response.body 中读取一块数据
              // value 是一个  Uint8Array(length) 对象
              const { done, value } = await reader.read()

              // 当数据都被读取完时， done 为 true，就是说没有数据了
              if (done) {
                // 读取完毕以后。 value 就是undefined
                // console.log('读取完成');
                break
              }

              // 把这块数据放入我们自己的流中
              // console.log('读取到数据了');
              controller.enqueue(value);

            }

            // 读取完成后，关闭流
            controller.close();

            // 	释放 reader 的“锁”，表示我们不再读取了
            reader.releaseLock();
          }
        })

        // 我们从 fetch 得到的流中“接水”，然后再“倒”进我们自建的流 rs 中。

        // console.log('rs', rs);
        // 创建一个新的 Response 对象，指定 MIME type; 如果没有指定 MIME type， 则到blob 对象是type是空的
        const r2 = new Response(rs, { headers: { 'Content-Type': 'image/svg+xml' } })

        const blob = await r2.blob()
        console.log(blob);


        image.src = URL.createObjectURL(blob)
      } catch (error) {
        console.log('报错了')
        console.log(error)
      }
    }

    // run()

    // 上面是原始的, 下面结合了 下载进度的实现

    const run2 = async () => {
      try {
        const response = await fetch('./2.png');
        if (!response.ok) {
          throw new Error('网络请求失败');
        }


        const contentLength = response.headers.get('Content-Length');

        // 动态获取图片的类型
        const contentType = response.headers.get('Content-Type') || 'image/*';


        const total = contentLength ? parseInt(contentLength, 10) : 0;
        let loaded = 0;

        // 这里的 body 是一个 ReadableStream 对象
        const reader = response.body.getReader();

        // 	new ReadableStream 创建一个自定义的读取流对象
        const rs = await new ReadableStream({
          // 	start 当流开始时会执行这个函数 - 这是内置的函数
          async start (controller) {
            while (true) {
              // 	reader.read 从上面获取的 response.body 中读取一块数据
              // value 是一个  Uint8Array(length) 对象
              const { done, value } = await reader.read()

              // 当数据都被读取完时， done 为 true，就是说没有数据了
              if (done) {
                // 读取完毕以后。 value 就是undefined
                // console.log('读取完成');
                break
              }

              // 模拟慢速加载
              await delay(50);



              // 把这块数据放入我们自己的流中
              // console.log('读取到数据了');
              controller.enqueue(value);

              loaded += value.length;
              // 模拟慢速加载
              await delay(1000);

              if (total) {
                const percent = Math.floor((loaded / total) * 100);
                progressBar.value = percent;
                statusText.textContent = percent + '%';
              }
            }

            // 读取完成后，关闭流
            controller.close();

            // 	释放 reader 的“锁”，表示我们不再读取了
            reader.releaseLock();
          }
        })

        // 我们从 fetch 得到的流中“接水”，然后再“倒”进我们自建的流 rs 中。

        // console.log('rs', rs);
        // 创建一个新的 Response 对象，指定 MIME type; 如果没有指定 MIME type， 则到blob 对象是type是空的
        const r2 = new Response(rs, { headers: { 'Content-Type':contentType } })

        const blob = await r2.blob()
        console.log(blob);


        image3.src = URL.createObjectURL(blob)


        // 加载完成，隐藏 loading 动画
        loadingIndicator.style.display = 'none';
      } catch (error) {
        console.log('报错了')
        console.log(error)
      }
    }
    run2()


  </script>
</body>

</html>